package com.fy.service.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.fy.common.constant.CmdConstants;
import com.fy.common.constant.RedisKeyConstant;
import com.fy.common.dto.UserReqestDto;
import com.fy.common.dto.UserRequestHandleDto;
import com.fy.common.entity.*;
import com.fy.common.enums.SkImChatSessionEnum;
import com.fy.common.enums.SkImCommonStatusEnum;
import com.fy.common.enums.SkImGroupEnum;
import com.fy.common.enums.SkImUserRequestEnum;
import com.fy.common.model.PageRequest;
import com.fy.common.model.im.MessageModel;
import com.fy.common.util.ImUtil;
import com.fy.common.util.TokenUtil;
import com.fy.common.vo.UserRequestVo;
import com.fy.dao.mapper.SkImGroupMapper;
import com.fy.dao.mapper.SkImUserRequestMapper;
import com.fy.framework.common.model.R;
import com.fy.framework.component.config.LocaleMessage;
import com.fy.framework.component.config.RedissonComponet;
import com.fy.framework.component.config.TenantContextHolder;
import com.fy.service.service.*;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RMapCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author zhshuo
 * @date 2021/12/02 17:05
 **/
@Slf4j
@Service
public class SkImUserRequestServiceImpl extends ServiceImpl<SkImUserRequestMapper, SkImUserRequest>
        implements SkImUserRequestService {

    LocaleMessage localeMessage;
    MessageService messageService;
    ImBrokerService imBrokerService;
    SkImGroupMapper imGroupService;
    RedissonComponet redissonComponet;
    SkImUserInfoService userInfoService;
    SkImUserBacklistService backlistService;
    SkImUserFriendsService userFriendsService;
    SkImChatSessionService imChatSessionService;
    SkImGroupMemberService imGroupMemberService;

    @Override
    public R<?> pull(UserReqestDto userReqestDto) {
        SkImUserRequestEnum requestType = userReqestDto.getRequestType();
        Long targetId = userReqestDto.getTargetId();

        MessageModel messageModel = new MessageModel();
        messageModel.setFrom(TokenUtil.getUserId());
        messageModel.setTenantId(TenantContextHolder.getTenant());

        if (requestType.equals(SkImUserRequestEnum.FRIEND)) {
            // 请求添加好友
            if (userReqestDto.getSkImUserId().equals(targetId)) {
                return R.failedAlter(localeMessage.getMessage("im.user.cannotAddMyselfAsAFriend"));
            }

            SkImUserBacklist backlist = backlistService.selectOne(new EntityWrapper<SkImUserBacklist>()
                    .eq("sk_im_user_id", userReqestDto.getSkImUserId())
                    .eq("sk_im_black_user_id", targetId).eq("status",SkImCommonStatusEnum.NORAML.getStatus()));
            if (Objects.nonNull(backlist)) {
                return R.failedAlter(localeMessage.getMessage("im.user.userHasBeenBlockByYou"));
            }

            SkImUserFriends userFriends = userFriendsService.selectOne(new EntityWrapper<SkImUserFriends>()
                    .eq("sk_im_user_id", userReqestDto.getSkImUserId())
                    .eq("target_user_id", targetId));
            if (Objects.nonNull(userFriends)) {
                return R.failedAlter(localeMessage.getMessage("im.user.cannotAddFriendsRepeatedly"));
            }

            messageModel.setCmd(CmdConstants.RESPONSE_ADD_FRIEND);

        }else {
            RMapCache<String, Object> groupMember = redissonComponet.getMap(RedisKeyConstant.GROUP_MEMBERS+targetId.toString());
            if (groupMember.containsKey(TokenUtil.getUserId().toString())) {
                return R.failedAlter(localeMessage.getMessage("im.user.alreadyAMemberOfTheGroup"));
            }
            messageModel.setCmd(CmdConstants.RESPONSE_ADD_GROUP_REQUEST);
        }

        SkImUserRequest userRequest = selectOne(new EntityWrapper<SkImUserRequest>().eq("sk_im_user_id", userReqestDto.getSkImUserId())
                .eq("target_id", targetId).eq("status", SkImCommonStatusEnum.NORAML.getStatus()));

        boolean res = false;
        if(Objects.isNull(userRequest)){
            res = insert(new SkImUserRequest().setRequestRemark(userReqestDto.getRemark())
                    .setRequestType(requestType.getValue()).setSkImUserId(userReqestDto.getSkImUserId())
                    .setTargetId(targetId).setStatus(SkImUserRequestEnum.PROCESSING.getValue()));
        }else{
            res = updateById(userRequest.setCreateTime(new Date()));
        }
        imBrokerService.commonAddressingMessage(messageModel,Collections.singletonList(targetId),false);
        return res ? R.success(localeMessage.getMessage("im.common.success"))
                : R.failedAlter(localeMessage.getMessage("im.common.failedful"));
    }

    @SneakyThrows
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<?> handle(UserRequestHandleDto requestHandleDto) {
        Long requestId = requestHandleDto.getRequestId();
        SkImUserRequest userRequest = selectOne(new EntityWrapper<SkImUserRequest>().eq("id", requestId));
        SkImUserInfo skImUserInfo = userInfoService.selectOne(new EntityWrapper<SkImUserInfo>().eq("sk_im_user_id", userRequest.getSkImUserId()));
        if(userRequest.getRequestType().equals(SkImUserRequestEnum.GROUP.getValue())){
            //群
            if (Objects.isNull(userRequest)) {
                return R.failedAlter(localeMessage.getMessage("im.user.userRequestNotExisted"));
            }
            if (!userRequest.getStatus().equals(SkImUserRequestEnum.PROCESSING.getValue())) {
                return R.failedAlter(localeMessage.getMessage("im.common.parameterError"));
            }

            SkImGroup skImGroup = imGroupService.selectById(userRequest.getTargetId());
            SkImUserRequestEnum userRequestEnum = requestHandleDto.getUserRequestEnum();
            if (userRequestEnum.equals(SkImUserRequestEnum.AGREE)) {
                SkImGroupMember skImGroupMember = new SkImGroupMember().setInviteUser(userRequest.getInviteUser())
                        .setUserRole(SkImGroupEnum.GROUP_MEMBER.getValue()).setSkImGroupId(skImGroup.getId())
                        .setGroupNickName(skImGroup.getName()).setSkImUserId(userRequest.getSkImUserId())
                        .setUserNickName(skImUserInfo.getUsername()).setJoinWay(SkImGroupEnum.JOIN_INVITE.getValue());
                imGroupMemberService.insert(skImGroupMember);
                updateById(new SkImUserRequest().setId(requestId).setRemark(requestHandleDto.getRefuseRemark())
                        .setStatus(userRequestEnum.getValue()).setHandleTime(new Date()));

                SkImChatSession chatSession = new SkImChatSession().setSessionId(ImUtil.chatSessionIdGenGroup(userRequest.getSkImUserId(), userRequest.getTargetId()))
                        .setSkImUserId(userRequest.getSkImUserId()).setTargetId(userRequest.getTargetId()).setType(SkImChatSessionEnum.GROUP.getType()).setStatus(0);
                imChatSessionService.insert(chatSession);

                RMapCache<String, Object> groupMember = redissonComponet.getMap(RedisKeyConstant.GROUP_MEMBERS+skImGroup.getId());
                groupMember.put(userRequest.getSkImUserId().toString(),new JSONObject());
                imGroupMemberService.updateGroupMemberCount(userRequest.getTargetId(),-1);
            }
        }else{
            //好友
            if(userRequest.getSkImUserId().equals(userRequest.getTargetId())){
                return R.failedAlter(localeMessage.getMessage("im.user.cannotAddMyselfAsAFriend"));
            }
            if (Objects.isNull(userRequest)) {
                return R.failedAlter(localeMessage.getMessage("im.user.userRequestNotExisted"));
            }
            if (!userRequest.getStatus().equals(SkImUserRequestEnum.PROCESSING.getValue())) {
                return R.failedAlter(localeMessage.getMessage("im.common.parameterError"));
            }

            SkImUserRequestEnum userRequestEnum = requestHandleDto.getUserRequestEnum();
            if (userRequestEnum.equals(SkImUserRequestEnum.AGREE)) {
                ArrayList<SkImUserFriends> userFriends = new ArrayList<>(2);
                userFriends.add(new SkImUserFriends().setSkImUserId(userRequest.getSkImUserId())
                        .setTargetUserId(userRequest.getTargetId()));
                userFriends.add(new SkImUserFriends().setSkImUserId(userRequest.getTargetId())
                        .setTargetUserId(userRequest.getSkImUserId()));
                userFriendsService.insertBatch(userFriends);

                updateById(new SkImUserRequest().setId(requestId).setRemark(requestHandleDto.getRefuseRemark())
                        .setStatus(userRequestEnum.getValue()).setHandleTime(new Date()));

                SkImUserInfo targetUserInfo = userInfoService.selectOne(new EntityWrapper<SkImUserInfo>().eq("sk_im_user_id", userRequest.getTargetId()));

                SkImChatSession chatSession = new SkImChatSession().setSessionId(ImUtil.chatSessionIdGenFriend(userRequest.getSkImUserId(), userRequest.getTargetId()))
                        .setSkImUserId(userRequest.getSkImUserId()).setTargetId(userRequest.getTargetId()).setType(SkImChatSessionEnum.FRIEND.getType()).setStatus(0)
                        .setAvatar(skImUserInfo.getAvatar()).setChatTitle(skImUserInfo.getUsername());
                imChatSessionService.insert(chatSession);
                SkImChatSession skImChatSession = new SkImChatSession().setSessionId(ImUtil.chatSessionIdGenFriend(userRequest.getTargetId(), userRequest.getSkImUserId()))
                        .setSkImUserId(userRequest.getTargetId()).setTargetId(userRequest.getSkImUserId()).setType(SkImChatSessionEnum.FRIEND.getType()).setStatus(0)
                        .setAvatar(targetUserInfo.getAvatar()).setChatTitle(targetUserInfo.getUsername());
                imChatSessionService.insert(skImChatSession);

                MessageModel messageModel = new MessageModel();
                messageModel.setFrom(userRequest.getTargetId());
                messageModel.setTo(userRequest.getSkImUserId());
                messageModel.setCmd(CmdConstants.RESPONSE_ADD_FRIEND);
                messageModel.setTenantId(TenantContextHolder.getTenant());
                messageService.saveSingleMessage(messageModel);
                imBrokerService.updateToSessionLastMessage(messageModel,chatSession);
                imBrokerService.updateFromSessionLastMessage(messageModel,skImChatSession);
            }
        }
        return R.success(localeMessage.getMessage("im.common.success"));
    }

    @Override
    public R<?> list(PageRequest<UserRequestVo> requestPageRequest) {
        List<SkImUserRequest> userRequestVoList =
                baseMapper.list(requestPageRequest,
                        requestPageRequest.getQueryParam().setSkImUserId(TokenUtil.getUserId()));
        List<UserRequestVo> userRequestVos = new ArrayList<>(userRequestVoList.size());
        Map<Integer, List<SkImUserRequest>> map =
                userRequestVoList.stream().collect(Collectors.groupingBy(SkImUserRequest::getRequestType));
        Optional.ofNullable(map.get(SkImUserRequestEnum.FRIEND.getValue())).ifPresent(skImUserRequests -> {
            Map<Long, SkImUserInfo> userInfoMap =
                    userInfoService
                            .selectList(new EntityWrapper<SkImUserInfo>().in("sk_im_user_id",
                                    skImUserRequests.stream().map(SkImUserRequest::getSkImUserId).collect(Collectors.toSet())))
                            .stream().collect(Collectors.toMap(SkImUserInfo::getSkImUserId, Function.identity()));
            userRequestVoList.forEach(skImUserRequest -> Optional.of(userInfoMap.get(skImUserRequest.getSkImUserId()))
                    .ifPresent(skImUserInfo -> userRequestVos.add(new UserRequestVo().setAvatar(skImUserInfo.getAvatar())
                            .setTargetUserName(skImUserInfo.getUsername()).setRequestId(skImUserRequest.getId())
                            .setRequestRemark(skImUserRequest.getRequestRemark()).setStatus(skImUserRequest.getStatus())
                            .setSkImUserId(skImUserRequest.getSkImUserId()))));
        });
        requestPageRequest.setRecords(userRequestVos);
        return R.success(requestPageRequest);
    }

    @Autowired
    public void setLocaleMessage(LocaleMessage localeMessage) {
        this.localeMessage = localeMessage;
    }

    @Autowired
    public void setMessageService(MessageService messageService) {
        this.messageService = messageService;
    }
    @Autowired
    public void setImBrokerService(ImBrokerService imBrokerService) {
        this.imBrokerService = imBrokerService;
    }
    @Autowired
    public void setImGroupService(SkImGroupMapper imGroupService) {
        this.imGroupService = imGroupService;
    }
    @Autowired
    public void setRedissonComponet(RedissonComponet redissonComponet) {
        this.redissonComponet = redissonComponet;
    }
    @Autowired
    public void setUserInfoService(SkImUserInfoService userInfoService) {
        this.userInfoService = userInfoService;
    }
    @Autowired
    public void setBacklistService(SkImUserBacklistService backlistService) {
        this.backlistService = backlistService;
    }
    @Autowired
    public void setUserFriendsService(SkImUserFriendsService userFriendsService) {
        this.userFriendsService = userFriendsService;
    }
    @Autowired
    public void setImChatSessionService(SkImChatSessionService imChatSessionService) {
        this.imChatSessionService = imChatSessionService;
    }
    @Autowired
    public void setImGroupMemberService(SkImGroupMemberService imGroupMemberService) {
        this.imGroupMemberService = imGroupMemberService;
    }
}